package com.zmn.plat.anole.impl;

import com.google.common.collect.Lists;
import com.zmn.anole.dubbo.interfaces.AnoleRemoteService;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.plat.anole.interfaces.IEncryptDecrypt;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.common.util.encrypt.EncryptDecryptUtils;
import com.zmn.plat.common.util.encrypt.annotation.EncryptDecryptField;
import com.zmn.plat.dubbo.utils.DubboConsts;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 描述: 加解密接口实现
 *
 * @author jiafei
 * @version v1.0
 * @since 2021/8/26 18:31
 */
@Slf4j
@Component
public class EncryptDecryptImpl implements IEncryptDecrypt {

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    AnoleRemoteService anoleRemoteService;

    private static final int CONCURRENCY_BOUNDARY = 1000;

    private static final int SINGLE_BOUNDARY = 50;

    private static final String DECRYPT = "DECRYPT";

    @Override
    public <T> T encrypt(T parameterObject) throws IllegalAccessException {

        Map<String, String> encryptMap = EncryptDecryptUtils.encryptFields(parameterObject);
        if (CollectionUtil.isNullOrEmpty(encryptMap)) {
            return parameterObject;
        }
        ResponseDTO<Map<String, String>> responseDTO = null;
        try {
            responseDTO = anoleRemoteService.batchEncryptMap(encryptMap);
        } catch (Exception e) {
            log.error("解密失败...,type:{}", e.getMessage(), e);
        }
        if (!responseDTO.isSuccess()) {
            log.error("【{}】数据加密失败:{}", this.getClass(), responseDTO);
            throw new PlatException("数据加密失败");
        }

        Map<String, String> encryptData = responseDTO.getData();
        return EncryptDecryptUtils.backFillData(parameterObject, encryptData);

    }

    @Override
    public <T> List<T> decrypt(List<T> result, String key) throws IllegalAccessException {

        // 判断是否有需要解密的字段
        Annotation annotation = EncryptDecryptUtils.getAnnotation(result.get(0), EncryptDecryptField.class);
        if (Objects.isNull(annotation)) {
            return result;
        }

        if (result.size() <= SINGLE_BOUNDARY) {
            return singleEncryptDecrypt(result, DECRYPT);
        } else {
            return batchEncryptDecrypt(result, key, DECRYPT);
        }
    }

    public <T> List<T> singleEncryptDecrypt(List<T> result, String type) throws IllegalAccessException {

        for (T t : result) {
            Map<String, String> encryptDecryptMap = EncryptDecryptUtils.encryptdecrypt(t);
            if (CollectionUtil.isNullOrEmpty(encryptDecryptMap)) {
                continue;
            }
            ResponseDTO<Map<String, String>> responseDTO = null;
            try {
                if (DECRYPT.equals(type)) {
                    responseDTO = anoleRemoteService.batchDecryptMap(encryptDecryptMap);
                } else {
                    responseDTO = anoleRemoteService.batchEncryptMap(encryptDecryptMap);
                }
            } catch (Exception e) {
                log.error("解密失败...,type:{}", e.getMessage(), e);
            }
            if (!responseDTO.isSuccess()) {
                log.error("【{}】数据加密解密失败:{}", this.getClass(), responseDTO);
                throw new PlatException("数据加密解密失败");
            }
            Map<String, String> encryptDecryptData = responseDTO.getData();
            EncryptDecryptUtils.backFillData(t, encryptDecryptData);
        }
        return result;
    }


    public <T> List<T> batchEncryptDecrypt(List<T> result, String key, String type) throws IllegalAccessException {

        Map<String, Map<String, String>> encryptDecryptData = new HashMap<>(result.size());
        for (List<T> list : Lists.partition(result, CONCURRENCY_BOUNDARY)) {
            Map<String, Map<String, String>> encryptDecryptMap = EncryptDecryptUtils.batchEncryptDecrypt(list, key);
            for (Map.Entry<String, Map<String, String>> entry : encryptDecryptMap.entrySet()) {
                ResponseDTO<Map<String, String>> responseDTO = null;
                try {
                    if (DECRYPT.equals(type)) {
                        responseDTO = anoleRemoteService.batchDecryptMap(entry.getValue());
                    } else {
                        responseDTO = anoleRemoteService.batchEncryptMap(entry.getValue());
                    }
                } catch (Exception e) {
                    log.error("解密失败...,type:{}", type, e.getMessage(), e);
                }
                if (!responseDTO.isSuccess()) {
                    log.error("【{}】批量数据加密解密失败:{}", this.getClass(), responseDTO);
                    throw new PlatException("批量数据加密解密失败");
                }
                encryptDecryptData.put(entry.getKey(), responseDTO.getData());
            }
            // 解密
            EncryptDecryptUtils.batchBackFillData(list, encryptDecryptData, key);
        }

        return result;
    }

}
